package com.common.orm;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class DBIssuesResolver {
    private ClassData classData;

    ClassData getClassData() {
        return classData;
    }

    void setClassData(ClassData classData) {
        this.classData = classData;
    }
    
    public  boolean resolveProblem(Connection conn,String error) throws SQLException{
        Pattern p=Pattern.compile("\\[SQLITE_ERROR\\].*?\\(no such table\\:\\s*(.*?)\\)");
        Matcher m=p.matcher(error);
        if(m.find()){
            String tableName=m.group(1);
            resolveNotSuchTable(conn,tableName);
            return true;
        }
        
        p=Pattern.compile("\\[SQLITE_ERROR\\].*\\(no such column\\:\\s*(.*?)\\)");
        m=p.matcher(error);
        if(m.find()){
            String columnName=m.group(1);
            resolveNotSuchField(conn,classData.getTableName(),columnName);
            return true;
        }
        
        String noSuchTableError="no such table:";
        if(error.toLowerCase().startsWith(noSuchTableError)){
            String tableName=error.substring(noSuchTableError.length()+1);
            resolveNotSuchTable(conn,tableName);
            return true;
        }
        String []result=match("\\(table (.*) has no column named (.*)\\)", error);
        if(result!=null){
            resolveNotSuchField(conn, result[0], result[1]);
            return true;
        }
        String noSuchField="no such column:";
        if(error.toLowerCase().startsWith(noSuchField)){
            String fieldName=error.substring(noSuchField.length()+1);
            resolveNotSuchField(conn,classData.getTableName(), fieldName);
            return true;
        }
        return false;
    }
    
    private String[] match(String pattern, String str){
        Pattern p=Pattern.compile(pattern);
        Matcher m=p.matcher(str);
        if(m.find()){
            ArrayList<String>groups=new ArrayList<String>();
            for(int i=0;i<m.groupCount();i++){
                groups.add(m.group(1+i));
            }

            return groups.toArray(new String[0]);
        }
        return null;
    }
    private void resolveNotSuchField(Connection conn,String tableName, String fieldName) throws SQLException{
        String ft=getDatabaseFieldType(fieldName);
        String lastWord="";
        if(classData.getColumnsMap().get(fieldName).isPrimaryKey()){
            lastWord=" PRIMARY KEY AUTOINCREMENT";
        }
        String sql="ALTER TABLE "+tableName+" ADD "+fieldName+" "+ft+lastWord;
        PreparedStatement statement= conn.prepareStatement(sql);
        statement.execute();
        statement.close();
    }
    
    private String getDatabaseFieldType(String fieldName){
        MethodColumnPair mcp= classData.getColumnsMap().get(fieldName);
        String name=mcp.getFieldType().getName();
        if(name.equals("int") || name.equals("java.lang.Integer")){
            return "integer";
        }
        
        if(name.equals("double") || name.equals("java.lang.Double")){
            return "number";
        }
        
        if(name.equals("float") || name.equals("java.lang.Float")){
            return "number";
        }
        
        if(name.equals("java.lang.String")){
            return "varchar";
        }
        return "integer";
    }
    
    private void resolveNotSuchTable(Connection conn,String tableName) throws SQLException{
        String sql;
        if(classData.getPrimaryKey()==null){
            sql="CREATE TABLE "+tableName+" ( id integer);";
        }else{
            String primaryName=classData.getPrimaryKey().getColumn();
            sql="CREATE TABLE "+tableName+" ( "+primaryName+" integer PRIMARY KEY)";
        }
        PreparedStatement statement= conn.prepareStatement(sql);
        statement.execute();
        statement.close();
    }
}
